"use client"; import * as React from "react"; import { useState, useTransition, useEffect } from "react"; import { Settings, Plus, Users } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"; import { Badge } from "@/components/ui/badge"; import { toast } from "sonner"; import { DepartmentTreeView } from "./department-tree-view"; import { DepartmentDomainAssignmentDialog } from "./department-domain-assignment-dialog"; import { type DepartmentNode } from "@/lib/users/knox-service"; import { assignDomainToDepartments, getDepartmentDomainAssignments, autoAssignUsersDomains, type UserDomain } from "@/lib/users/department-domain/service"; import { DOMAIN_OPTIONS } from "./domain-constants"; interface DepartmentMenuAccessManagerProps { departmentsPromise: Promise; companyInfo: { code: string; name: string }; } interface DepartmentAssignment { id: number; departmentCode: string; departmentName: string; assignedDomain: string; description?: string | null; } export function DepartmentMenuAccessManager({ departmentsPromise, companyInfo }: DepartmentMenuAccessManagerProps) { const [departments, setDepartments] = useState([]); const [selectedDepartments, setSelectedDepartments] = useState([]); const [assignments, setAssignments] = useState([]); const [isDialogOpen, setIsDialogOpen] = useState(false); const [isPending, startTransition] = useTransition(); const [isDepartmentsLoading, setIsDepartmentsLoading] = useState(true); const [isAssignmentsLoading, setIsAssignmentsLoading] = useState(true); // Promise를 해결하여 부서 데이터 로드 useEffect(() => { const loadDepartments = async () => { setIsDepartmentsLoading(true); try { const departmentTree = await departmentsPromise; setDepartments(departmentTree); } catch (error) { console.error("부서 트리 로드 실패:", error); toast.error("부서 정보를 불러오는데 실패했습니다."); setDepartments([]); } finally { setIsDepartmentsLoading(false); } }; loadDepartments(); }, [departmentsPromise]); // 기존 할당 정보 로드 useEffect(() => { const loadAssignments = async () => { setIsAssignmentsLoading(true); try { const assignmentData = await getDepartmentDomainAssignments(); setAssignments(assignmentData as DepartmentAssignment[]); } catch (error) { console.error("할당 정보 로드 실패:", error); toast.error("할당 정보를 불러오는데 실패했습니다."); setAssignments([]); } finally { setIsAssignmentsLoading(false); } }; loadAssignments(); }, []); // 선택된 부서들의 정보 가져오기 const getSelectedDepartmentInfo = React.useCallback(() => { const findDepartment = (nodes: DepartmentNode[], code: string): DepartmentNode | null => { for (const node of nodes) { if (node.departmentCode === code) { return node; } const found = findDepartment(node.children, code); if (found) return found; } return null; }; return selectedDepartments .map(code => findDepartment(departments, code)) .filter(Boolean) as DepartmentNode[]; }, [departments, selectedDepartments]); // 도메인 할당 처리 const handleDomainAssign = async (assignmentData: { departmentCodes: string[]; domain: string; description?: string; }) => { // 선택된 부서들의 이름 매핑 생성 const departmentNames: Record = {}; const collectDepartmentNames = (nodes: DepartmentNode[]) => { nodes.forEach(node => { if (assignmentData.departmentCodes.includes(node.departmentCode)) { departmentNames[node.departmentCode] = node.departmentName || node.departmentCode; } collectDepartmentNames(node.children); }); }; collectDepartmentNames(departments); startTransition(async () => { try { const result = await assignDomainToDepartments({ departmentCodes: assignmentData.departmentCodes, domain: assignmentData.domain as UserDomain, description: assignmentData.description, departmentNames, }); if (result.success) { toast.success(result.message); setSelectedDepartments([]); // 할당 정보 새로고침 try { const updatedAssignments = await getDepartmentDomainAssignments(); setAssignments(updatedAssignments as DepartmentAssignment[]); } catch (error) { console.error("할당 정보 새로고침 실패:", error); } // users 테이블에 도메인 동기화 작업 진행 try { const syncResult = await autoAssignUsersDomains(); if (syncResult.success && syncResult.assignedCount > 0) { toast.success(`사용자 도메인 동기화 완료: ${syncResult.assignedCount}명의 사용자가 자동 할당되었습니다.`); } } catch (error) { console.error("사용자 도메인 동기화 실패:", error); // 동기화 실패해도 메인 할당은 성공이므로 에러 토스트는 표시하지 않음 } } else { toast.error(result.message); } } catch (error) { console.error("도메인 할당 실패:", error); toast.error("도메인 할당 중 오류가 발생했습니다."); } }); }; const canAssign = selectedDepartments.length > 0; const selectedDepartmentInfo = getSelectedDepartmentInfo(); const isLoading = isDepartmentsLoading || isAssignmentsLoading; return (
{/* 왼쪽: 조직도 트리 */}
조직도 - {companyInfo.name} 부서를 선택하여 도메인을 할당하세요. 상위 부서 선택 시 하위 부서들도 자동으로 포함됩니다. {isLoading ? (

조직도를 불러오는 중...

) : ( )}
{/* 오른쪽: 선택된 부서 정보 및 할당 버튼 */}
{/* 선택된 부서 정보 */} 선택된 부서 {selectedDepartments.length}개 부서가 선택되었습니다 {selectedDepartmentInfo.length === 0 ? (
부서를 선택해주세요
) : (
{selectedDepartmentInfo.map((dept) => { const assignment = assignments.find(a => a.departmentCode === dept.departmentCode); return (
{dept.departmentName || dept.departmentCode}
{dept.departmentCode}
{assignment && ( {assignment.assignedDomain} )}
); })}
)}
{/* 도메인 할당 버튼 */} 도메인 할당 선택된 부서들에 도메인을 할당합니다 {canAssign && (
상위 부서를 선택한 경우 하위 부서들도 자동으로 동일한 도메인이 할당됩니다.
)}
{/* 범례 */} 도메인 범례
{DOMAIN_OPTIONS.map((option) => (
{option.value} {option.description}
))}
{/* 도메인 할당 다이얼로그 */}
); }